// Game.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "resource.h"
#include "Game.h"
#include "InputManager/InputManager.h"
	
#define MAX_LOADSTRING 100
#define WINDOW_WIDTH 1280
#define WINDOW_HEIGHT 720

// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name

// Forward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
HWND				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK	About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: Place code here.
	MSG msg;
	HWND hWnd;

	// Initialize global strings
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_GAME, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// Perform application initialization:
	hWnd = InitInstance(hInstance, nCmdShow);
	if (!hWnd)
	{
		return FALSE;
	}

	// Game initialization
	Game game;
	SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG)&game);
	game.Initialize(hWnd, WINDOW_WIDTH, WINDOW_HEIGHT, FALSE);

	// Main message loop:
	while (true)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			// Test if this is a quit
			if (msg.message == WM_QUIT)
				break;

			// Translate any accelerator keys
			TranslateMessage(&msg);
			// Send the message to the window proc
			DispatchMessage(&msg);
		}
		else
		{
			// Game logic
			if (!game.GameLoop())
				PostQuitMessage(0);
		}
	}

	// Game shutdown
	game.Shutdown();

	return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GAME));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_GAME);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
HWND InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   RECT window = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};

   AdjustWindowRectEx(&window, WS_SYSMENU, FALSE, WS_EX_APPWINDOW);

   hWnd = CreateWindow(szWindowClass, szTitle, WS_SYSMENU,
	   (GetSystemMetrics(SM_CXSCREEN) - WINDOW_WIDTH) / 2, (GetSystemMetrics(SM_CYSCREEN) - WINDOW_HEIGHT) / 2,
	   WINDOW_WIDTH, WINDOW_HEIGHT, HWND_DESKTOP, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return hWnd;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_DESTROY	- post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	Game* game = (Game *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
	InputManager * inputManager = nullptr;
	if (game)
		inputManager = game->GetInputManager();

	switch (message)
	{
	case WM_LBUTTONUP:
		inputManager->UpdateState(LEFT_MOUSE, INPUT_UP);
		break;
	case WM_LBUTTONDOWN:
		inputManager->UpdateState(LEFT_MOUSE, INPUT_DOWN);
		break;
	case WM_RBUTTONUP:
		inputManager->UpdateState(RIGHT_MOUSE, INPUT_UP);
		break;
	case WM_RBUTTONDOWN:
		inputManager->UpdateState(RIGHT_MOUSE, INPUT_DOWN);
		break;
	case WM_KEYUP:
		inputManager->UpdateInputState(wParam, INPUT_UP);
		break;
	case WM_KEYDOWN:
		inputManager->UpdateInputState(wParam, INPUT_DOWN);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}